package tau_sadna.tau_map;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Date;

import org.mapsforge.core.graphics.Bitmap;
import org.mapsforge.core.model.BoundingBox;
import org.mapsforge.core.model.LatLong;
import org.mapsforge.core.model.MapPosition;
import org.mapsforge.map.android.graphics.AndroidGraphicFactory;
import org.mapsforge.map.android.view.MapView;
import org.mapsforge.map.layer.renderer.TileRendererLayer;
import org.mapsforge.map.model.MapViewPosition;
import org.mapsforge.map.reader.MapDatabase;
import org.mapsforge.map.reader.header.FileOpenResult;
import org.mapsforge.map.reader.header.MapFileInfo;
import org.mapsforge.map.util.MapViewProjection;

import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.DrawerLayout;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;


public class MainActivity extends BasicMapViewer {
	private static final int LOW_DPI_STATUS_BAR_HEIGHT = 19;
	private static final int MEDIUM_DPI_STATUS_BAR_HEIGHT = 25;
	private static final int HIGH_DPI_STATUS_BAR_HEIGHT = 38;
	
	public static final String LAST_TIME_DOWNLOAD = "last_time_download";
	public static final double HOUR_TO_WAIT = 3.0;
	
	public static final String LANG_KEY = "language";
	public static final int ENGLISH = 0;
	public static final int HEBREW = 1;
	
	//maximal number of search results
	private static final int MAX_RESULTS = 4;
	
	//display size
	protected double WIDTH;
	protected double HEIGHT;
	
	protected MapView mapView;
	protected RelativeLayout mainLayout;
	protected OurDrawerLayout dlayout;
	protected LayerXmlParser parser;
	protected CompassGPS gpsOveray;
	
	//the currently displayed result (that is, the last one selected)
	public Result currentResult = null;
	OurImageView dirArrow;
	
	GpsIcon gpsIcon;
	
	//this is a temporary setting. language is set
	//upon creation by getLangFromPreferences
	public static int language = 0;
	public GlassView uiGlass;
	
	//The current top window. This is either a list of results or
	//an ExtraInfo window. It is closed when clicked outside.
	private View currentWindow;
	
	private List<TauLayer> possibleLayers;
	
	protected boolean arrowNotInit = true;
	private int mInterval = 100;
	private Handler mHandler;
	Runnable mStatusChecker = new Runnable() {
	    @Override 
	    public void run() {
	    	if(arrowNotInit){
	    		initDirArrow();
	    	} else {
	    		handleDirArrow();
	    	}
	    	mHandler.postDelayed(mStatusChecker, mInterval);
	    }
	};
	
	private int sInterval = 10 * 1000;
	Runnable gpsChecker = new Runnable() {
	    @Override 
	    public void run() {
	    	if(gpsOveray != null)
	    		gpsOveray.checkGpsWorking();
	    	mHandler.postDelayed(gpsChecker, sInterval);
	    }
	};
	
	private int minInterval = 15 * 60 * 1000;
	Runnable downloadChecker = new Runnable() {
	    @Override 
	    public void run() {
	    	if(!DownloadManager.isDownloading()){
	    		if((new File(DownloadManager.Config+DownloadManager.Temp)).exists() || timePassed()) {
	    			download();
	    		}
	    	}
	    	mHandler.postDelayed(downloadChecker, minInterval);
	    }
	};
	
	/**
	 * 
	 * @return true if enough time passed, and false otherwise.
	 */
	public boolean timePassed() {
		long time = (new Date()).getTime()-sharedPreferences.getLong(LAST_TIME_DOWNLOAD, 0);
		if(time >= (long)(1000 * 60 * 60 * HOUR_TO_WAIT)){
			return true;
		}
		return false;
	}
	
	/**
	 * start to download.
	 */
	protected void download() {
		Toast.makeText(this, "Starting to download", Toast.LENGTH_SHORT).show();
		(new DownloadManager()).execute(this);
	}

	@Override
    public void onCreate(Bundle savedInstanceState) {
		readMarkerOffsets(); // read marker pictures offsets.
		
		FileIO.initiate(this);
		
		possibleLayers = new LinkedList<TauLayer>();
		try {
			writeMapFileToSDCard();
			writeLayersToSDCard();
			Log.i("MainActivity","Storing theme file");
			storeResource(R.raw.tau_theme,getThemeFile());
		} catch (IOException e) {
			//TODO proper error handling
			e.printStackTrace();
		}
		
		
		//initialize the map view
        super.onCreate(savedInstanceState);
        //set size & position
        setPosition();
        setSize();
        
        //hide the keyboard
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

		
		parser = new LayerXmlParser();
		parser.init(this);
		Log.i("MainActivity","My parser got "+parser.permLayers.size()+" layers");
		
		
		
        
        mapView = mapViews.get(0);
        mainLayout = mainViewInit();
        recapDisplayedLayers();
        mHandler = new Handler();
        mStatusChecker.run();
        gpsChecker.run();
        downloadChecker.run();
    }
	
	protected void readMarkerOffsets() {
		TauLayer.setOffsetMul("marker_red", -0.5);	
	}

	@SuppressWarnings("deprecation")
	@SuppressLint("NewApi")
	private void setSize() {
		// getting size of display. 
		Display display = getWindowManager().getDefaultDisplay();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2){
	        Point size = new Point();
        	display.getSize(size);
        	WIDTH = size.x;
        	HEIGHT = size.y;
        } else {
            WIDTH = display.getWidth();
            HEIGHT = display.getHeight();
        }
		DisplayMetrics displayMetrics = new DisplayMetrics();
		((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(displayMetrics);

		int statusBarHeight;

		switch (displayMetrics.densityDpi) {
		    case DisplayMetrics.DENSITY_HIGH:
		        statusBarHeight = HIGH_DPI_STATUS_BAR_HEIGHT;
		        break;
		    case DisplayMetrics.DENSITY_MEDIUM:
		        statusBarHeight = MEDIUM_DPI_STATUS_BAR_HEIGHT;
		        break;
		    case DisplayMetrics.DENSITY_LOW:
		        statusBarHeight = LOW_DPI_STATUS_BAR_HEIGHT;
		        break;
		    default:
		        statusBarHeight = MEDIUM_DPI_STATUS_BAR_HEIGHT;
		}
		
		HEIGHT -= statusBarHeight;
	}

	private void recapDisplayedLayers() {
		Log.i("MainActivity", "Recapping displayed layers:");
		for (TauLayer l : possibleLayers) {
			String show = sharedPreferences.getString(l.name_en, null);
			l.removeFrom(mapView);
			Log.i("MainActivity", "Recap: layer: "+l.name_en+" - preference: "+show);
			if (show != null && show.equals("shown")) {
				l.addTo(mapView);
				Log.i("MainActivity", "Showing layer: "+l.name_en);
			} else {
				Log.i("MainActivity", "Not showing layer: "+l.name_en);
			}
		}
	}
	
	@Override
    public void onResume() {
        super.onResume();
        Log.i("MainActivity", "on resume triggered");
        this.gpsOveray.enableMyLocation(true);
        recapDisplayedLayers();
        if (currentResult != null) {
        	showResult(currentResult);
        }
    }

    
    @Override
	public void onPause() {
    	gpsOveray.disableMyLocation();
	    super.onPause();
	}
   
	  @Override
	protected File getMapFile() {
		String map_filename = getMapFileName();
		return new File(getFilesDir() + File.separator + map_filename);
	}
	  
		
	private File getThemeFile() {
		String theme_filename = getResources().getString(R.string.theme_filename);
		return new File(getFilesDir() + File.separator + theme_filename);
	}
	  
	@Override
	protected String getMapFileName() {
		return "_"+ language + getResources().getString(R.string.map_filename);
	}
	
	protected String getMapFileNameEnd() {
		return getResources().getString(R.string.map_filename);
	}
	
	@Override
	protected void createSharedPreferences() {
		super.createSharedPreferences();
		language = getLangFromPreferences();
	}
	
	
	/**
	 * Set zoom levels, bounding box, and starting position (if needed).
	 */
	protected void setPosition(){
		Log.i("MainActivity","setting map position");
        mapViewPositions.get(0).setZoomLevelMin((byte)15);
        if(mapViewPositions.get(0).getZoomLevel() < mapViewPositions.get(0).getZoomLevelMin()){ 
        	mapViewPositions.get(0).setZoomLevel((byte)16);
        }
        
        BoundingBox bb = new BoundingBox(32.1062, 34.7950, 32.1211, 34.8100);
        mapViewPositions.get(0).setMapLimit(bb);
        
        if(!bb.contains(mapViewPositions.get(0).getCenter())){
        	mapViewPositions.get(0).setCenter(bb.getCenterPoint());
        }
        Log.i("MainActivity","map position set successfully");
	}
    
	@Override
	protected MapPosition getInitialPosition() {
		MapDatabase mapDatabase = new MapDatabase();
		final FileOpenResult result = mapDatabase.openFile(getMapFile());
		if (result.isSuccess()) {
			final MapFileInfo mapFileInfo = mapDatabase.getMapFileInfo();
			if (mapFileInfo != null && mapFileInfo.startPosition != null) {
				return new MapPosition(mapFileInfo.startPosition, (byte) mapFileInfo.startZoomLevel);
			} else {
				return new MapPosition(new LatLong(32.11, 34.8), (byte) 12);
			}
		}
		throw new IllegalArgumentException("Invalid Map File " + getMapFileName()+" ("+result.getErrorMessage()+")");
	}
	
    /**
     * Initialize the main layout (ViewGroup), adding all views to be in tree which he is root of.
     * @return the main layout.
     */
    @SuppressLint("NewApi")
	protected RelativeLayout mainViewInit(){
    	RelativeLayout mainLayout = new RelativeLayout(this);
    	setContentView(mainLayout);
    	
        mainLayout.addView(mapView);
        
        RelativeLayout v = (RelativeLayout) getLayoutInflater().inflate(R.layout.activity_main, null);
        uiGlass = new GlassView(this);
        v.addView(uiGlass,0);
        mainLayout.addView(v);
        mainLayout.bringChildToFront(v);
        try {
        EditText searchText = (EditText) v.findViewById(R.id.ui_view).findViewById(R.id.search_text);
        searchText.addTextChangedListener(new TextWatcher() {
			
			@Override
			public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
				
			}
			
			@Override
			public void beforeTextChanged(CharSequence cs, int arg1, int arg2,
					int arg3) {
				
			}
			
			@Override
			public void afterTextChanged(Editable e) {
				EditText searchText = (EditText) getMainRelativeLayout().findViewById(R.id.search_text);
				onSearch(searchText);
			}
		});
        } catch (Exception e) {
        	Log.e("MainActivity",e.toString());
        }

        dlayout = drawerLayerInit();
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
        mainLayout.addView(dlayout, params);
        mainLayout.bringChildToFront(dlayout);
        
       
		RelativeLayout.LayoutParams bottomLeft = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.WRAP_CONTENT,
				RelativeLayout.LayoutParams.WRAP_CONTENT);
		bottomLeft.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
		bottomLeft.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
		
		// calculate scale bar height including it margins
		int scaleBarHeight = (int) (5 + 50*mapView.getModel().displayModel.getScaleFactor());
		bottomLeft.setMargins(bottomLeft.leftMargin+10, bottomLeft.topMargin, bottomLeft.rightMargin, bottomLeft.bottomMargin+ scaleBarHeight);
		
        gpsIcon = new GpsIcon(this);
        OnClickListener clicklistenr = new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				gpsOveray.centerAt();
				gpsOveray.setSnapToLocationEnabled(true);
				AnimationDrawable anim;
				switch (gpsIcon.state) {
					case GpsIcon.STATE_OFF:
						gpsIcon.setBackgroundResource(R.drawable.gps_anim_off);
						anim = (AnimationDrawable) gpsIcon.getBackground();
						anim.stop();
						anim.start();
						break;
					case GpsIcon.STATE_ON:
						gpsIcon.setBackgroundResource(R.drawable.gps_anim_on);
						anim = (AnimationDrawable) gpsIcon.getBackground();
						anim.stop();
						anim.start();
						break;
					default:
						break;
				}
			}
		};
        gpsIcon.setOnClickListener(clicklistenr);
        //gpsIcon.setImageDrawable(getResources().getDrawable(R.drawable.gps_icon2));
        mainLayout.addView(gpsIcon,bottomLeft);
        
        dlayout.bringToFront();

        dirArrow = new OurImageView(this);
        dirArrow.setImageDrawable(getResources().getDrawable(R.drawable.direction_arrow2));
        mainLayout.addView(dirArrow);
        dirArrow.setX(-5000);
        
        return mainLayout;
    }

    public void setGpsIconState(int state) {
    	gpsIcon.setState(state);
    }
    
    @SuppressLint("NewApi")
    /**
     * initialize the DirArrorw original width and height.
     */
	public void initDirArrow(){
    	if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
    		if(dirArrow.drawable != null) {
    			dirArrow.setOrginalHeight(((BitmapDrawable)dirArrow.drawable).getBitmap().getHeight());
    			dirArrow.setOrginalWidth(((BitmapDrawable)dirArrow.drawable).getBitmap().getWidth());
    			arrowNotInit = false;
    		}
    		return;
    	}
    	
    	//due to bug that in early build the dirArrow getting smaller than need to sample it during use. 
    	dirArrow.setX(0);
		dirArrow.setY(0);
		dirArrow.setRotation(0);
    	if(dirArrow.getWidth() != 0){
    		dirArrow.setOrginalHeight(dirArrow.getHeight());
    		dirArrow.setOrginalWidth(dirArrow.getWidth());
    		arrowNotInit = false;
    	}
    }
    
    @SuppressLint("NewApi")
	public void handleDirArrow() {
    	if (currentResult == null) {
    		dirArrow.setX(-5000);
    		return;
    	}
    	
    	HEIGHT = mapView.getHeight();
    	WIDTH = mapView.getWidth();
    	
    	int width = (int)WIDTH;
    	int height = (int)HEIGHT;
    	
    	LatLong ll = currentResult.getLatLong();
    	MapViewProjection proj = new MapViewProjection(mapView);
    	org.mapsforge.core.model.Point target = proj.toPixels(ll);
    	if (target.x <= width && target.x >= 0 && target.y <= height && target.y >= 0) {
    		dirArrow.setX(-5000);
    		return;
    	}
    	org.mapsforge.core.model.Point inSect = Utils.getIntersection(width, height, target.x, target.y);
    	int diffX = 0;
    	int diffY = 0;

    	double angle = Utils.getAngle(width/2, height/2, target.x, target.y);
    	int[] diff_xy = calcOffsetOfArrow(angle);
    	diffX = diff_xy[0];
    	diffY = diff_xy[1];
    	
    	dirArrow.setX((float) inSect.x + diffX);
    	dirArrow.setY((float) inSect.y + diffY);
    	dirArrow.setRotation((float) angle);
    }
    

    /**
     * calculate the offset so the arrow will be in position.
     * @param angle in degree.
     * @return offset in array, 0 place is x and 1 is y.
     */
    protected int[] calcOffsetOfArrow(double angle){
    	if(dirArrow == null)
    		return null;
    	
    	int[] ret = new int[2];
    	
    	//for calculation assume that (0,0) is in center.
    	
    	angle = Math.toRadians(angle);
    	double hWidth = dirArrow.getOrginalWidth()/2.0;
    	double hHeight;
    	
    	double xArrow = hWidth*Math.cos(-angle);
    	double yArrow = hWidth*Math.sin(-angle);
    	
    	hWidth = dirArrow.getWidth()/2.0;
    	hHeight = dirArrow.getHeight()/2.0;
    	
    	//place in corner and not in arrow end, fix it by calculate offset.
    	ret[0] = (int)(-hWidth - xArrow);
    	ret[1] = (int)(-hHeight + yArrow); // y is inverse in phones.
    	
    	return ret;
    }
    
    
    
    /**
     * Initialize the drawer layout (ViewGroup), which have all the options menus as his children.
     * @return the drawer layout.
     */
    protected OurDrawerLayout drawerLayerInit(){
    	OurDrawerLayout OurDrawerLayout = new OurDrawerLayout(this);
    	ScrollView scv;
    	
    	//add options menu drawer
    	int width = (int) (WIDTH*0.5);
    	int height = DrawerLayout.LayoutParams.MATCH_PARENT;
    	int gravity = Gravity.LEFT;
    	OurDrawerLayout.LayoutParams params = new OurDrawerLayout.LayoutParams(width, height, gravity);
    	
    	scv = optionMenuInit();
    	OurDrawerLayout.addView(scv, params);
    	
    	OurDrawerLayout.setDrawerLockMode(tau_sadna.tau_map.OurDrawerLayout.LOCK_MODE_UNLOCKED);
    	
    	return OurDrawerLayout;
    }
    
    
    /**
     * Initialize the option menu (ViewGroup,ScrollView).
     * @return the option menu.
     */
    protected ScrollView optionMenuInit(){
    	ScrollView sv = new ScrollView(this); 
    	LinearLayout menu = new LinearLayout(this);
    	sv.addView(menu);
    	menu.setOrientation(LinearLayout.VERTICAL);
    	
    	Button helpButton = new Button(this);
    	MLString helpButtonText = new MLString(
    			getResources().getString(R.string.help_button_en),
    			getResources().getString(R.string.help_button_he));
    	helpButton.setText(helpButtonText.getName());
    	helpButton.setOnClickListener(new OnClickListener() {
    		@Override
    		public void onClick(View v) {
    			setCurrentWindow(new HelpWindow(MainActivity.this));
    		}
    	});
    	menu.addView(helpButton);
    	
    	LinearLayout langMenu = LangOptionInit();
    	menu.addView(langMenu);
    	
    	Button button = new Button(this);
    	button.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				download();
			}
		});
    	button.setText(((new MLString(getResources().getString(R.string.en_download), getResources().getString(R.string.he_download))).getName()));
    	menu.addView(button);
    
    	
    	button = new Button(this);
    	button.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				restart(1000);;
			}
		});
    	button.setText(((new MLString(getResources().getString(R.string.en_restart), getResources().getString(R.string.he_restart))).getName()));
    	menu.addView(button);
    	
    	LinearLayout LayerMenu = layersMenuInit();
    	menu.addView(LayerMenu);
    	
    	sv.setBackgroundColor(Color.LTGRAY);
    	
    	return sv;
    }
    
    /**
     * Initialize the option for language.
     * @return the language menu option.
     */
    protected LinearLayout LangOptionInit(){
    	LinearLayout langOption = new LinearLayout(this);
    	langOption.setOrientation(LinearLayout.VERTICAL);
    	
    	TextView textView = new TextView(this);
		textView.setText("Choose Language:");
		textView.setTextSize(20);
		langOption.addView(textView);
		
		OnClickListener langChanger = new OnClickListener() {
			@Override
			public void onClick(View v) {
				int lang = ENGLISH;
				CharSequence langString = ((Button)(v)).getText();
				
				if(langString.equals("English")){
					lang = ENGLISH;
				} else if(langString.equals(getResources().getString(R.string.ivrit))){
					lang = HEBREW;
				}
				
				changeLang(lang);
			}
		};
		
		Button enButton = new Button(this);
		enButton.setText("English");
		enButton.setOnClickListener(langChanger);
		langOption.addView(enButton);
		
		Button heButton = new Button(this);
		heButton.setText(getResources().getString(R.string.ivrit));
		heButton.setOnClickListener(langChanger);
		langOption.addView(heButton);
    	
    	return langOption;
    }
    
    
    /**
     * Initialize the layers menu (ViewGroup,ScrollView).
     * @return the layers menu.
     */
    protected LinearLayout layersMenuInit(){
    	LinearLayout menu = new LinearLayout(this);
    	LinearLayout.LayoutParams buttonParams = new 
    			LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
    	buttonParams.setMargins(10, 0, 10, 0);
    	menu.setOrientation(LinearLayout.VERTICAL);
    	
    	for (TauLayer layer : parser.getDisplayedLayers()) {
    		Log.i("MainActivity","Adding button for layer "+layer.name_en);
    		LayerButton layerButton = new LayerButton(this, layer);
    		layerButton.setLayoutParams(buttonParams);
    		menu.addView(layerButton);
    		possibleLayers.add(layer);
		}
    	
    	return menu;
    }
    
    
    protected void writeMapFileToSDCard() {
    	String mapFilename = getMapFileNameEnd();
    	
    	//en
    	File file = new File(this.getFilesDir() + File.separator + "_0" + mapFilename);
    	storeResource(R.raw._0map,file);
    	
    	//he
    	file = new File(this.getFilesDir() + File.separator + "_1" + mapFilename);
    	storeResource(R.raw._1map,file);
    }
    
    //writes the resource to the specified file, unless it's already there
    private void storeResource(int res_id, File file) {
    	if (file.exists())
    		return;
    	try {
	        InputStream inputStream = getResources().openRawResource(res_id);
	        FileOutputStream fileOutputStream = new FileOutputStream(file);

	        byte buf[]=new byte[1024];
	        int len;
	        while((len=inputStream.read(buf))>0) {
	            fileOutputStream.write(buf,0,len);
	        }

	        fileOutputStream.close();
	        inputStream.close();
	    } catch (IOException e1) {
	    	Log.e("MainActivity","Error storing resource to file "+file.getAbsolutePath()+":"+e1.getMessage());
	    }
	}

	private void writeLayersToSDCard() throws IOException {
		Log.i("MainActivity","Layer names:"+getResources().getString(R.string.layer_names));
		String[] layerNames = getResources().getString(R.string.layer_names).split(",");
		for (String layerName : layerNames) {
			Log.i("MainActivity","Storing layer "+layerName);
			File storePosition = new File(getFilesDir() + File.separator + layerName + ".lay");
			int layerId = getResources().getIdentifier(layerName, "raw", "tau_sadna.tau_map");
			if (layerId == 0) {
				Log.e("MainActivity","Cannot find layer "+layerName);
				continue;
			}
			storeResource(layerId, storePosition);
		}
	}
	
	public void onSettings(MenuItem settingsButton) {
		dlayout.openDrawer(Gravity.LEFT);
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if(keyCode == KeyEvent.KEYCODE_MENU){
			// open close menu.
			if(dlayout.isDrawerOpen(Gravity.LEFT)){
				dlayout.closeDrawer(Gravity.LEFT);
			} else {
				dlayout.openDrawer(Gravity.LEFT);
			}
			
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}
    
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	@Override
	/**
	 * called by BaisicMapViewer.onCreat, before our onCreat
	 */
	protected void createLayers() {
		TileRendererLayer tileRendererLayer;
		try {
			tileRendererLayer = Utils.createTileRendererLayer(this.tileCache,
					this.mapViewPositions.get(0), getMapFile(), new TauTheme(getThemeFile()), false);
			this.layerManagers.get(0).getLayers().add(tileRendererLayer);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			Log.e("MainActivity","Fatal Error: cannot find theme");
			e.printStackTrace();
			return;
		}

		Drawable drawable = getResources().getDrawable(R.drawable.marker_green);
		Bitmap bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
		bitmap = Utils.rotateBitmap(bitmap, 180);
		MapViewPosition mapVeiwPosition = mapViewPositions.get(0);
		bitmap.incrementRefCount();
        gpsOveray = new CompassGPS(this, mapVeiwPosition, bitmap);
        gpsOveray.setSnapToLocationEnabled(true); // GPS follow me.
        this.layerManagers.get(0).getLayers().add(gpsOveray);
	}


	@Override
	protected MapView getMapView() {
		MapView mv = new MapView(this) {
			@Override
			public boolean onTouchEvent(MotionEvent ev) {
				if((ev.getAction() | MotionEvent.ACTION_MOVE) == ev.getAction()){
					gpsOveray.setSnapToLocationEnabled(false);
				}
				return super.onTouchEvent(ev);
			}
		};
		return mv;
	}
	
	public void onSearch(View v) {
		EditText searchBox = (EditText)findViewById(R.id.search_text);
		String query = searchBox.getText().toString();
		Result[] results = Search.search(query, parser.permLayers, MAX_RESULTS,this);
		ResultsView resultsList  = new ResultsView(this,results);
		RelativeLayout.LayoutParams resultsPos = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.WRAP_CONTENT, 
				RelativeLayout.LayoutParams.WRAP_CONTENT);
		resultsPos.addRule(RelativeLayout.BELOW, R.id.search_box);
		resultsPos.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
		resultsPos.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
		resultsList.setLayoutParams(resultsPos);
		setCurrentWindow(resultsList);
	}
	
	private void setCurrentWindow(View window) {
		closeCurrentWindow();
		dlayout.closeDrawers();
		currentWindow = window;
		uiGlass.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				closeCurrentWindow();
				uiGlass.setOnClickListener(null);
			}
			
		});
		getMainRelativeLayout().addView(window);
	}

	public RelativeLayout getMainRelativeLayout() {
		return (RelativeLayout) mainLayout.findViewById(R.id.above_map).findViewById(R.id.ui_view);
	}
	
	/**
	 * @return the current language to use.
	 */
	int getLangFromPreferences(){
		return sharedPreferences.getInt(LANG_KEY, ENGLISH);
	}

	public void showResult(Result result) {
		if (currentResult != null)
			currentResult.removeFrom(mapView);
		currentResult = result;
		result.addTo(mapView);
	}
	
	@Override
	public void onBackPressed() {
		//TODO only exit after a second press (first just shows "Press back again to quit")
		
		// close drawers.
		if(!dlayout.isAllDrawerClosed()){
			dlayout.closeDrawers();
			return;
		}
		
		if(closeCurrentWindow()){
			return;
		}
		
		if (currentResult != null) {
			currentResult.removeFrom(mapView);
			currentResult = null;
		} else
			super.onBackPressed();
	}
	
	public void addExtraInfo(ExtraInfo info) {
		RelativeLayout.LayoutParams belowSearchBar = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.WRAP_CONTENT, 
				RelativeLayout.LayoutParams.WRAP_CONTENT);
		belowSearchBar.addRule(RelativeLayout.CENTER_HORIZONTAL);
		belowSearchBar.addRule(RelativeLayout.BELOW, R.id.search_box);
		info.setLayoutParams(belowSearchBar);
		setCurrentWindow(info);
	}
	
	protected boolean closeCurrentWindow(){
		if (currentWindow != null) {
			getMainRelativeLayout().removeView(currentWindow);
			uiGlass.setOnClickListener(null);
			currentWindow = null;
			return true;
		}
		return false;
	}
	
	/**
	 * Change the language to lang.
	 * @param lang - the language to change to.
	 */
	protected void changeLang(int lang){
		int currentLang = sharedPreferences.getInt(LANG_KEY, language);
		if(currentLang != lang){
			Editor editor = sharedPreferences.edit();
			editor.putInt(LANG_KEY, lang);
			editor.commit();
		}
	}
	
	@Override
	public void onSharedPreferenceChanged(SharedPreferences preferences,
			String key) {
		super.onSharedPreferenceChanged(preferences, key);
		
		// if language was changed need to restart.
		if(key.equals(LANG_KEY)){
			Log.i("MainActivity","Language changed - restarting");
			restart(1000);
		}
	}
	
	/**
	 * Restart the app.
	 * @param interval - the time waited before restate from now.
	 */
	protected void restart(int interval){
		AlarmManager mgr = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
		PendingIntent RESTART_INTENT = PendingIntent.getActivity(this.getBaseContext(), 0, new Intent(getIntent()), getIntent().getFlags());
		mgr.set(AlarmManager.RTC, System.currentTimeMillis() + interval, RESTART_INTENT);
		System.exit(2);
	}

	/**
	 * open request restart button.
	 */
	public void requestRestart() {
		String text;
		String ButtonText;
		
		text = (new MLString(getResources().getString(R.string.en_restart_request), getResources().getString(R.string.he_restart_request)).getName());
		ButtonText = (new MLString(getResources().getString(R.string.en_restart), getResources().getString(R.string.he_restart)).getName());
		
		RestartRequest rr = new RestartRequest(this, text, ButtonText);
		
		RelativeLayout.LayoutParams belowSearchBar = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.WRAP_CONTENT, 
				RelativeLayout.LayoutParams.WRAP_CONTENT);
		belowSearchBar.addRule(RelativeLayout.CENTER_HORIZONTAL);
		belowSearchBar.addRule(RelativeLayout.BELOW, R.id.search_box);
		rr.setLayoutParams(belowSearchBar);
		setCurrentWindow(rr);
	}
}
